home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / util / misc / ReportPlus.lha / reportplus / source / f8.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-08-20  |  48.9 KB  |  1,576 lines

  1. #include <exec/types.h>
  2. #include <exec/memory.h>
  3. #include <proto/exec.h>
  4. #include <intuition/intuition.h>
  5. #include <intuition/gadgetclass.h>
  6. #include <proto/intuition.h>
  7. #include <libraries/gadtools.h>
  8. #include <proto/gadtools.h>
  9. #include <dos/dos.h>
  10. #include <dos/exall.h>
  11. #include <dos/dostags.h>
  12. #include <proto/dos.h>
  13. #include <graphics/gfx.h>
  14. #include <clib/graphics_protos.h>
  15. #include <clib/alib_protos.h>
  16. #include <libraries/asl.h>
  17. #include <clib/asl_protos.h>
  18.  
  19. #include <ctype.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "rp.h"
  23.  
  24. #define ALL_REACTION_CLASSES
  25. #include <reaction/reaction.h>
  26.  
  27. #define LIMIT_DIRS        8196
  28. #define SIZELISTVIEWCHARS 37
  29. #define TRUNCATE          40
  30. #define LVTRUNCATE        25
  31.  
  32. #define GID_8_LB1 0
  33. #define GIDS_8    GID_8_LB1
  34.  
  35. /* Limitations:
  36.    LIMIT_DIRS (top-level list entries).
  37.    MAX_FILES (total files/dirs in path). */
  38.  
  39. MODULE void pop(void);
  40. MODULE void push(STRPTR name, ULONG theindex);
  41. MODULE void subdir(ULONG theindex);
  42. MODULE void parent(void);
  43. MODULE void root(void);
  44. MODULE void pathasl(void);
  45. MODULE void pathstring(void);
  46. MODULE void comma(ULONG value);
  47. MODULE ABOOL dirasl(void);
  48. MODULE void showduplicates(void);
  49. MODULE void addduplicate(STRPTR path, STRPTR filename);
  50. MODULE void flipfind(ABOOL keyboard);
  51. MODULE void writeline(void);
  52.  
  53. MODULE struct ColumnInfo TheColumnInfo[] =
  54. { { 50,            // WORD   ci_Width
  55.     "Pathname",    // STRPTR ci_Title
  56.     0,             // ULONG  ci_Flags
  57.   },
  58.   { 10,
  59.     "Size",
  60.     0,
  61.   },
  62.   { 10,
  63.     "Date",
  64.     0,
  65.   },
  66.   { 30,
  67.     "Version",
  68.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  69.           to the right border of the relevant column). */
  70.   },
  71.   { -1, (STRPTR) ~0, -1
  72. } };
  73.  
  74. IMPORT struct Library*     ListBrowserBase;
  75. IMPORT ABOOL               fillwindows;
  76. IMPORT TEXT                asldir[VLONGFIELD + 1],
  77.                            aslresult[MEDFIELD + 1];
  78. MODULE TEXT                logstring[256 + 1],
  79.                            liststring[4][256 + 1];
  80. MODULE UBYTE               valuestring[11],
  81.                            commastring[14];
  82. MODULE struct Gadget*      gadgets[GIDS_8 + 1];
  83.  
  84. IMPORT  SBYTE              page;
  85. MODULE  ULONG              DirNamesAllocated  = 0,
  86.                            FileNamesAllocated = 0;
  87. IMPORT  TEXT               globalname[VLONGFIELD + 1];
  88. IMPORT  TEXT               weekdaystring[10],
  89.                            datestring[10],
  90.                            timestring[9];
  91. IMPORT struct SharedStruct shared;
  92. IMPORT struct NewGadget    Gadget;
  93. IMPORT struct Screen*      ScreenPtr;
  94. IMPORT struct Window*      MainWindowPtr;
  95. IMPORT struct Gadget      *BU99_Left,
  96.                           *BU99_Right,
  97.                           *ST99_Output,
  98.                           *BU99_OutputASL,
  99.                           *CB99_Log,
  100.                           *BU99_Update,
  101.                           *BU99_Stop,
  102.                           *GListPtr,
  103.                           *PrevGadPtr;
  104. IMPORT struct ExAllData*   EADataPtr;
  105. IMPORT TEXT                IOBuffer[LONGESTFIELD + 1];
  106.  
  107. #define MAX_FILES (128 * 1024)
  108.  
  109. MODULE ABOOL               DupNodes           = FALSE,
  110.                            EmptyColumnarNodes = FALSE,
  111.                            SizeNodes          = FALSE;
  112. MODULE struct List         SizeList,
  113.                            DupList,
  114.                            EmptyColumnarList;
  115. MODULE struct Gadget      *LV81_Listview = NULL,
  116.                           *CB81_Find     = NULL,
  117.                           *ST81_Path     = NULL,
  118.                           *BU81_PathASL  = NULL,
  119.                           *BU81_Root     = NULL,
  120.                           *BU81_Parent   = NULL,
  121.                           *TE81_Total    = NULL,
  122.                           *TE81_Free     = NULL,
  123.                           *TE81_Status   = NULL;
  124. MODULE ULONG              files          = 0;
  125. // how many files have been found. Counting from 1.
  126. MODULE STRPTR*            PathnamePtr;
  127. MODULE STRPTR*            FilenamePtr;
  128. MODULE STRPTR*            StackPtr;
  129. MODULE STRPTR*            DirNamePtr;
  130. MODULE ABOOL*             IsDup;
  131. MODULE UBYTE              pathlength;
  132. MODULE BPTR               DirHandle      = NULL,
  133.                           LogFileHandle  = NULL;
  134.  
  135. MODULE struct
  136. {   ULONG entries, totalbytesval, freeval, stackentries;
  137.     TEXT  totalbytesstring[11], freestring[11],
  138.           oldpath[VLONGFIELD + 1], path[VLONGFIELD + 1];
  139.     ULONG bytes[LIMIT_DIRS], topdir[LIMIT_DIRS];
  140.     LONG  type[LIMIT_DIRS];
  141.     ABOOL finddup;
  142. } size;
  143. MODULE ABOOL stop;
  144.  
  145. AGLOBAL void size_init(void)
  146. {   struct Node* ListBrowserNodePtr;
  147.  
  148.     strcpy(size.path, "RAM:");
  149.     size.finddup = FALSE;
  150.  
  151.     NewList(&EmptyColumnarList);
  152.     if (!(ListBrowserNodePtr = AllocListBrowserNode
  153.     (   4,                  // columns
  154.         /* LBNCA_ tags are those that apply to the specific column. */
  155.         LBNA_Column,        0,
  156.         LBNA_Column,        1,
  157.         LBNA_Column,        2,
  158.         LBNA_Column,        3,
  159.         TAG_END
  160.     )))
  161.     {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  162.     }
  163.     AddTail(&EmptyColumnarList, ListBrowserNodePtr); // AddTail() has no return code
  164.     EmptyColumnarNodes = TRUE;
  165. }
  166.  
  167. AGLOBAL void size1(void)
  168. {   verynewwindow
  169.     (   SIZE1WIDTH, SIZE1HEIGHT,
  170.         "Report+: Path Size Report",
  171.         BUTTONIDCMP | STRINGIDCMP | LISTVIEWIDCMP
  172.     );
  173.     if (fillwindows)
  174.     {   SetAPen(MainWindowPtr->RPort, 0);
  175.         RectFill(MainWindowPtr->RPort,  12,  44,  12 + 348,  44 + 126 - 3);     // LV81_Listview
  176.         RectFill(MainWindowPtr->RPort, 228, 168, 228 + 116, 168 + 12);          // TE81_Total
  177.         RectFill(MainWindowPtr->RPort, 228, 180, 228 + 116, 180 + 12);          // TE81_Free
  178.         RectFill(MainWindowPtr->RPort, 562,  20, 562 +  68,  20 + 12);          // TE81_Status
  179.     }
  180.  
  181.     /* We can't just use EmptyList, we actually need the LBNA_Column
  182.     tags such as in EmptyColumnarList.
  183.  
  184.     LISTBROWSER_ScrollRaster seems not to be usable with
  185.     multi-column lists. */
  186.  
  187.     if (!(gadgets[GID_8_LB1] = (struct Gadget *) NewObject
  188.     (   LISTBROWSER_GetClass(),     NULL,
  189.         GA_ID,                      GID_8_LB1,
  190.         GA_Left,                    10,
  191.         GA_Top,                     226,
  192.         GA_Width,                   620,
  193.         GA_Height,                  262,
  194.         GA_ReadOnly,                TRUE,
  195.         GA_TextAttr,                Gadget.ng_TextAttr,
  196.         GA_Disabled,                !size.finddup,
  197.         LISTBROWSER_Labels,         (ULONG) &EmptyColumnarList,
  198.         LISTBROWSER_ColumnInfo,     (ULONG) &TheColumnInfo,
  199.         LISTBROWSER_ColumnTitles,   TRUE,
  200.         LISTBROWSER_HorizontalProp, TRUE,
  201.         LISTBROWSER_VirtualWidth,   620 + 155,
  202.         TAG_END
  203.     )))
  204.     {   rq("Can't create ReAction gadgets!");
  205.     }
  206.     AddGList(MainWindowPtr, gadgets[GID_8_LB1], -1, -1, NULL);
  207.     RefreshGList(gadgets[GID_8_LB1], MainWindowPtr, NULL, -1);
  208.  
  209.     /* path */
  210.     setgadget(60, 20, 268, 12, "_Path:", NULL);
  211.     ST81_Path = PrevGadPtr = (struct Gadget *) CreateGadget
  212.     (   STRING_KIND,
  213.         PrevGadPtr,
  214.         &Gadget,
  215.         GTST_String, &(size.path),
  216.         GTST_MaxChars, VLONGFIELD,
  217.         GA_TabCycle, TRUE,
  218.         GT_Underscore, '_',
  219.         TAG_DONE
  220.     );
  221.     /* path... */
  222.     setgadget(330, 20, 28, 12, "_...", NULL);
  223.     BU81_PathASL = PrevGadPtr = (struct Gadget *) CreateGadget
  224.     (   BUTTON_KIND,
  225.         PrevGadPtr,
  226.         &Gadget,
  227.         GT_Underscore, '_',
  228.         TAG_DONE
  229.     );
  230.     // root
  231.     setgadget(10, 32, 174, 12, "_Root", NULL);
  232.     BU81_Root = PrevGadPtr = (struct Gadget *) CreateGadget
  233.     (   BUTTON_KIND,
  234.         PrevGadPtr,
  235.         &Gadget,
  236.         GT_Underscore, '_',
  237.         TAG_DONE
  238.     );
  239.     // parent
  240.     setgadget(184, 32, 174, 12, "P_arent", NULL);
  241.     BU81_Parent = PrevGadPtr = (struct Gadget *) CreateGadget
  242.     (   BUTTON_KIND,
  243.         PrevGadPtr,
  244.         &Gadget,
  245.         GT_Underscore, '_',
  246.         TAG_DONE
  247.     );
  248.  
  249.     setgadget(10, 44, 348, 126, NULL, NULL);
  250.     LV81_Listview = PrevGadPtr = (struct Gadget *) CreateGadget
  251.     (   LISTVIEW_KIND,
  252.         PrevGadPtr,
  253.         &Gadget,
  254.         GTLV_Labels, NULL,
  255.         TAG_DONE
  256.     );
  257.  
  258.     /* total bytes */
  259.     setgadget(226, 168, 116, 12, "Path bytes:", NULL);
  260.     TE81_Total = PrevGadPtr = (struct Gadget *) CreateGadget
  261.     (   TEXT_KIND,
  262.         PrevGadPtr,
  263.         &Gadget,
  264.         GTTX_Text, size.totalbytesstring,
  265.         GTTX_Border, TRUE,
  266.         TAG_DONE
  267.     );
  268.     /* free bytes */
  269.     setgadget(226, 180, 116, 12, "Free bytes:", NULL);
  270.     TE81_Free = PrevGadPtr = (struct Gadget *) CreateGadget
  271.     (   TEXT_KIND,
  272.         PrevGadPtr,
  273.         &Gadget,
  274.         GTTX_Text, size.freestring,
  275.         GTTX_Border, TRUE,
  276.         TAG_DONE
  277.     );
  278.  
  279.     // log to file?
  280.     setgadget(368, 45, 0, 0, "_Log to file?", PLACETEXT_RIGHT);
  281.     CB99_Log = PrevGadPtr = (struct Gadget *) CreateGadget
  282.     (   CHECKBOX_KIND,
  283.         PrevGadPtr,
  284.         &Gadget,
  285.         GTCB_Checked, shared.log,
  286.         GT_Underscore, '_',
  287.         TAG_DONE
  288.     );
  289.     /* output */
  290.     if (!shared.output[0])
  291.         strcpy(shared.output, "RAM:Report.txt");
  292.     setgadget(368, 72, 234, 12, "_Output pathname:", PLACETEXT_ABOVE);
  293.     ST99_Output = PrevGadPtr = (struct Gadget *) CreateGadget
  294.     (   STRING_KIND,
  295.         PrevGadPtr,
  296.         &Gadget,
  297.         GTST_String, &(shared.output),
  298.         GTST_MaxChars, LONGFIELD,
  299.         GA_TabCycle, TRUE,
  300.         GT_Underscore, '_',
  301.         TAG_DONE
  302.     );
  303.     /* output... */
  304.     setgadget(602, 72, 28, 12, "...", NULL);
  305.     BU99_OutputASL = PrevGadPtr = (struct Gadget *) CreateGadget
  306.     (   BUTTON_KIND,
  307.         PrevGadPtr,
  308.         &Gadget,
  309.         TAG_DONE
  310.     );
  311.  
  312.     // find duplicates?
  313.     setgadget( 10, 212, 0, 0, "Find _duplicates?", PLACETEXT_RIGHT);
  314.     CB81_Find = PrevGadPtr = (struct Gadget *) CreateGadget
  315.     (   CHECKBOX_KIND,
  316.         PrevGadPtr,
  317.         &Gadget,
  318.         GTCB_Checked, size.finddup,
  319.         GT_Underscore, '_',
  320.         TAG_DONE
  321.     );
  322.  
  323.     /* update */
  324.     setgadget(368, 20, 60, 12, "_Update", NULL);
  325.     BU99_Update = PrevGadPtr = (struct Gadget *) CreateGadget
  326.     (   BUTTON_KIND,
  327.         PrevGadPtr,
  328.         &Gadget,
  329.         GT_Underscore, '_',
  330.         TAG_DONE
  331.     );
  332.     /* stop */
  333.     setgadget(428, 20, 60, 12, "Stop", NULL);
  334.     BU99_Stop = PrevGadPtr = (struct Gadget *) CreateGadget
  335.     (   BUTTON_KIND,
  336.         PrevGadPtr,
  337.         &Gadget,
  338.         GA_Disabled, TRUE,
  339.         TAG_DONE
  340.     );
  341.  
  342.     // status
  343.     setgadget(558, 20, 72, 12, "Status:", NULL);
  344.  
  345.     TE81_Status = PrevGadPtr = (struct Gadget *) CreateGadget
  346.     (   TEXT_KIND,
  347.         PrevGadPtr,
  348.         &Gadget,
  349.         GTTX_Text, "Ready",
  350.         GTTX_Border, TRUE,
  351.         TAG_DONE
  352.     );
  353.  
  354.     drawgadgets((UWORD) ~0);
  355.  
  356.     if (!shared.log)
  357.     {   GT_SetGadgetAttrs
  358.         (   ST99_Output,
  359.             MainWindowPtr, NULL,
  360.             GA_Disabled, TRUE,
  361.             TAG_DONE
  362.         );
  363.         GT_SetGadgetAttrs
  364.         (   BU99_OutputASL,
  365.             MainWindowPtr, NULL,
  366.             GA_Disabled, TRUE,
  367.             TAG_DONE
  368.         );
  369.     }
  370.     updatesize();
  371.     ActivateGadget(ST81_Path, MainWindowPtr, NULL);
  372.     loop();
  373.     strcpy
  374.     (   shared.output,
  375.         ((struct StringInfo *) ST99_Output->SpecialInfo)->Buffer
  376.     );
  377.     closewindow();
  378.     size_exit();
  379. }
  380.  
  381. AGLOBAL void updatesize(void)
  382. {   BOOL                  more; // note that it is BOOL, not ABOOL
  383.     TEXT                  tempstring1[16], tempstring2[SIZELISTVIEWCHARS + 1],
  384.                           tempstring3[VLONGFIELD + 1], tempname[LONGFIELD + 1];
  385.     ULONG                 i, j, tempbytes;
  386.     LONG                  templength, temptype; // these both MUST be signed
  387.     ABOOL                 failed      = FALSE;
  388.     struct FileInfoBlock* FIBPtr      = NULL;
  389.     struct InfoData*      InfoDataPtr = NULL;
  390.     struct ExAllControl*  eac         = NULL;
  391.     struct ExAllData*     ead;
  392.  
  393.     if (SizeNodes)
  394.     {   clearlist(&SizeList);
  395.         SizeNodes = FALSE;
  396.     }
  397.     if (!DirNamePtr)
  398.     {   if (!(DirNamePtr = AllocVec(LIMIT_DIRS * sizeof(STRPTR), NULL)))
  399.         {   rq("Out of memory!");
  400.     }   }
  401.  
  402.     // 1: (Un)ghost relevant gadgets, for duration of the operation.
  403.  
  404.     stop = FALSE;
  405.     GT_SetGadgetAttrs
  406.     (   BU99_Update,
  407.         MainWindowPtr, NULL,
  408.         GA_Disabled, TRUE,
  409.         TAG_DONE
  410.     );
  411.     GT_SetGadgetAttrs
  412.     (   BU99_Stop,
  413.         MainWindowPtr, NULL,
  414.         GA_Disabled, FALSE,
  415.         TAG_DONE
  416.     );
  417.     GT_SetGadgetAttrs
  418.     (   BU99_Right,
  419.         MainWindowPtr, NULL,
  420.         GA_Disabled, TRUE,
  421.         TAG_DONE
  422.     );
  423.     GT_SetGadgetAttrs
  424.     (   TE81_Status,
  425.         MainWindowPtr, NULL,
  426.         GTTX_Text, "Reading",
  427.         TAG_DONE
  428.     );
  429.  
  430.     // 2: Now we get a Lock() on the path.
  431.  
  432.     size.stackentries = size.entries = 0;
  433.     /* From RKRM I&A, p. 65: */
  434.     if
  435.     (   !(DirHandle = (BPTR) Lock(size.path, ACCESS_READ))
  436.      || !(FIBPtr    = AllocDosObject(DOS_FIB, NULL))
  437.      || !(            Examine(DirHandle, FIBPtr))
  438.      ||  (FIBPtr->fib_DirEntryType <= 0) // if not a directory
  439.     )
  440.     {   failed = TRUE;
  441.     }
  442.  
  443.     strcpy(size.oldpath, size.path);
  444.     if (FIBPtr)
  445.     {   FreeDosObject(DOS_FIB, FIBPtr);
  446.         FIBPtr = NULL;
  447.     }
  448.     if (failed)
  449.     {   DisplayBeep(ScreenPtr);
  450.         GT_SetGadgetAttrs
  451.         (   BU99_Right,
  452.             MainWindowPtr, NULL,
  453.             GA_Disabled, FALSE,
  454.             TAG_DONE
  455.         );
  456.         GT_SetGadgetAttrs
  457.         (   BU99_Update,
  458.             MainWindowPtr, NULL,
  459.             GA_Disabled, FALSE,
  460.             TAG_DONE
  461.         );
  462.         GT_SetGadgetAttrs
  463.         (   BU99_Stop,
  464.             MainWindowPtr, NULL,
  465.             GA_Disabled, TRUE,
  466.             TAG_DONE
  467.         );
  468.         strcpy(size.path, size.oldpath);
  469.         GT_SetGadgetAttrs
  470.         (   ST81_Path,
  471.             MainWindowPtr, NULL,
  472.             GTST_String, size.path,
  473.             TAG_DONE
  474.         );
  475.         GT_SetGadgetAttrs
  476.         (   TE81_Status,
  477.             MainWindowPtr, NULL,
  478.             GTTX_Text, "Failed",
  479.             TAG_DONE
  480.         );
  481.         return;
  482.     }
  483.  
  484.     GT_SetGadgetAttrs
  485.     (   ST81_Path,
  486.         MainWindowPtr, NULL,
  487.         GTST_String, size.path,
  488.         TAG_DONE
  489.     );
  490.  
  491.     /* 3: Now we call Info() to ascertain the free bytes.
  492.           InfoDataPtr must be longword-aligned. */
  493.  
  494.     if (!(InfoDataPtr = AllocVec(sizeof(struct InfoData), MEMF_CLEAR)))
  495.     {   rq("Out of memory!");
  496.     }
  497.     if (Info(DirHandle, InfoDataPtr))
  498.     {   size.freeval =
  499.         (InfoDataPtr->id_NumBlocks - InfoDataPtr->id_NumBlocksUsed) *
  500.          InfoDataPtr->id_BytesPerBlock;
  501.         stcl_d(tempstring1, size.freeval);
  502.         templength = 10 - strlen(tempstring1);
  503.         strcpy(size.freestring, "");
  504.         for (i = 1; i <= templength; i++)
  505.             strcat(size.freestring, " ");
  506.         strcat(size.freestring, tempstring1);
  507.     } else strcpy(size.freestring, "         ?");
  508.     FreeVec(InfoDataPtr);
  509.     InfoDataPtr = NULL;
  510.  
  511.     /* 4: Now we are ready to begin the main part of the operation.
  512.  
  513.     size.topdir[]     = the 'owning' top-level directory for this subdir.
  514.                         Top-level dirs are owned by themselves.
  515.     size.bytes[]      = the size of this top-level directory/file.
  516.     size.entries      = how many top-level dirs, ie. how many names in the
  517.                         listview gadget.
  518.     size.path         = the path (drive, partition, etc.) the user is doing
  519.                         the report on.
  520.     size.stackentries = the current size of the stack.
  521.     DirNamesAllocated = the number of allocated chunks for the
  522.                         topdir names. */
  523.  
  524.     if (!(        StackPtr = AllocVec(LIMIT_DIRS * sizeof(STRPTR), NULL)))
  525.     {   rq("Out of memory!");
  526.     }
  527.  
  528.     files = 0;
  529.     if (size.finddup)
  530.     {   if (!( PathnamePtr = AllocVec(MAX_FILES * sizeof(STRPTR), NULL)))
  531.         {   rq("Out of memory!");
  532.         }
  533.         if (!( FilenamePtr = AllocVec(MAX_FILES * sizeof(STRPTR), NULL)))
  534.         {   rq("Out of memory!");
  535.         }
  536.         if (!(       IsDup = AllocVec(MAX_FILES * sizeof(ABOOL) , NULL)))
  537.         {   rq("Out of memory!");
  538.     }   }
  539.  
  540.     // This must be allocated with AllocDosObject()
  541.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  542.     {   rq("Can't allocate DOS object!");
  543.     }
  544.  
  545.     eac->eac_LastKey = 0;
  546.     do
  547.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 2048, ED_SIZE, eac);
  548.         if (!more && IoErr() != ERROR_NO_MORE_ENTRIES)
  549.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  550.             eac = NULL;
  551.             rq("Can't examine path!");
  552.         }
  553.         if (eac->eac_Entries == 0)
  554.         {   ; /* ExAll() failed normally with no entries */
  555.             continue; /* more is USUALLY zero */
  556.         }
  557.  
  558.         // OK, ExAll() has generated up to 2K of data.
  559.         ead = (struct ExAllData *) EADataPtr;
  560.         do
  561.         {   /* use ead here */
  562.  
  563.             if (ead->ed_Type == -3 || ead->ed_Type == 2) // if a normal file or normal directory (ie. not a link)
  564.             {   size.entries++;
  565.                 if (size.entries == LIMIT_DIRS)
  566.                 {   FreeDosObject(DOS_EXALLCONTROL, eac);
  567.                     eac = NULL;
  568.                     rq("Overflow!");
  569.                 }
  570.                 size.type[size.entries] = ead->ed_Type;
  571.                 if (size.entries > DirNamesAllocated)
  572.                 {   if (!(DirNamePtr[DirNamesAllocated + 1] = AllocMem(VLONGFIELD, MEMF_PUBLIC)))
  573.                     {   FreeDosObject(DOS_EXALLCONTROL, eac);
  574.                         eac = NULL;
  575.                         rq("Out of memory!");
  576.                     }
  577.                     DirNamesAllocated++;
  578.                 }
  579.                 strcpy(DirNamePtr[size.entries], ead->ed_Name);
  580.                 if (ead->ed_Type == 2) /* +2 is dir, +3 is softlink, -3 is file */
  581.                 {   size.bytes[size.entries] = 0;
  582.                     strcpy(tempstring3, size.path);
  583.                     if (!AddPart(tempstring3, ead->ed_Name, VLONGFIELD))
  584.                     {   FreeDosObject(DOS_EXALLCONTROL, eac);
  585.                         eac = NULL;
  586.                         rq("Can't add filename to pathname!");
  587.                     }
  588.                     push(tempstring3, size.entries);
  589.                 } else
  590.                 {   addduplicate("", ead->ed_Name);
  591.                     size.bytes[size.entries] = ead->ed_Size;
  592.             }   }
  593.  
  594.             /* get next ead */
  595.             ead = ead->ed_Next;
  596.         } while(ead);
  597.     } while(more);
  598.  
  599.     FreeDosObject(DOS_EXALLCONTROL, eac);
  600.     eac = NULL;
  601.     UnLock(DirHandle);
  602.     DirHandle = NULL;
  603.     pop();
  604.  
  605.     // Now handle the list.
  606.  
  607.     GT_SetGadgetAttrs
  608.     (   LV81_Listview,
  609.         MainWindowPtr,
  610.         NULL,
  611.         GTLV_Labels, (~0),
  612.         TAG_DONE
  613.     );
  614.  
  615.     if (!stop)
  616.     {   /* size.entries is the actual number of entries. The array elements are
  617.         from 1 to size.entries.
  618.  
  619.         bubble sort routine */
  620.         GT_SetGadgetAttrs
  621.         (   TE81_Status,
  622.             MainWindowPtr, NULL,
  623.             GTTX_Text, "Sorting",
  624.             TAG_DONE
  625.         );
  626.         for (i = size.entries; i >= 2; i--)
  627.         {   for (j = 2; j <= i; j++) 
  628.             {   if (size.bytes[j - 1] < size.bytes[j]) 
  629.                 {   // swap them
  630.                     tempbytes = size.bytes[j - 1];
  631.                     size.bytes[j - 1] = size.bytes[j]; 
  632.                     size.bytes[j] = tempbytes;
  633.                     temptype = size.type[j - 1];
  634.                     size.type[j - 1] = size.type[j];
  635.                     size.type[j] = temptype;
  636.                     strcpy(tempname, DirNamePtr[j - 1]);
  637.                     strcpy(DirNamePtr[j - 1], DirNamePtr[j]);
  638.                     strcpy(DirNamePtr[j], tempname);
  639.         }   }   }
  640.  
  641.         getdate();
  642.         if (shared.log)
  643.         {   tempstring1[0] = QUOTE;
  644.             tempstring1[1] = 0;
  645.     
  646.             strcpy(logstring, "Path: ");
  647.             strcat(logstring, tempstring1);
  648.             strcat(logstring, size.path);
  649.             strcat(logstring, tempstring1);
  650.             strcat(logstring, " at ");
  651.             strcat(logstring, timestring);
  652.             strcat(logstring, " on ");
  653.             strcat(logstring, weekdaystring);
  654.             strcat(logstring, " ");
  655.             strcat(logstring, datestring);
  656.             strcat(logstring, ":\n");
  657.             if (!(LogFileHandle = (BPTR) Open(shared.output, MODE_READWRITE)))
  658.                 rq("Can't open file for appending!");
  659.             Seek(LogFileHandle, 0, OFFSET_END);
  660.             writeline();
  661.         }
  662.  
  663.         // very long dirnames (truncated ones) are not selectable, unfortunately.
  664.         size.totalbytesval = 0;
  665.         for (i = 1; i <= size.entries; i++)
  666.         {   comma(size.bytes[i]);
  667.     
  668.             if (size.type[i] == 2)
  669.             {   strcpy(tempstring2, "*");
  670.                 strcpy(tempstring3, "*");
  671.             } else
  672.             {   strcpy(tempstring2, " ");
  673.                 strcpy(tempstring3, " ");
  674.             }
  675.  
  676.             if (strlen(DirNamePtr[i]) > TRUNCATE)
  677.                 *(DirNamePtr[i] + TRUNCATE) = 0; // truncate
  678.             strcat(tempstring3, DirNamePtr[i]);
  679.             templength = TRUNCATE - strlen(DirNamePtr[i]);
  680.             if (templength >= 1)
  681.                 for (j = 1; j <= templength; j++)
  682.                     strcat(tempstring3, " ");
  683.  
  684.             if (strlen(DirNamePtr[i]) > LVTRUNCATE)
  685.                 *(DirNamePtr[i] + LVTRUNCATE) = 0; // truncate
  686.             strcat(tempstring2, DirNamePtr[i]); /* tempstring2 = "*<name>" */
  687.             templength = LVTRUNCATE + 1 - strlen(DirNamePtr[i]);
  688.             if (templength >= 1)
  689.                 for (j = 1; j <= templength; j++)
  690.                     strcat(tempstring2, " "); /* tempstring2 = "*<name>   " */
  691.  
  692.             strcat(tempstring2, commastring);
  693.             strcat(tempstring3, commastring);
  694.  
  695.             AddNameToTail(&SizeList, tempstring2);
  696.             SizeNodes = TRUE;
  697.             if (shared.log)
  698.             {   strcpy(logstring, tempstring3);
  699.                 strcat(logstring, "\n");
  700.                 writeline();
  701.             }
  702.             size.totalbytesval += size.bytes[i];
  703.         }
  704.  
  705.         comma(size.totalbytesval);
  706.         GT_SetGadgetAttrs
  707.         (   TE81_Total,
  708.             MainWindowPtr, NULL,
  709.             GTTX_Text, commastring,
  710.             TAG_DONE
  711.         );
  712.         comma(size.freeval);
  713.         GT_SetGadgetAttrs
  714.         (   TE81_Free,
  715.             MainWindowPtr,
  716.             NULL,
  717.             GTTX_Text, commastring,
  718.             TAG_DONE
  719.         );
  720.         if (shared.log)
  721.         {   strcpy(logstring, "\nPath bytes:                              ");
  722.             comma(size.totalbytesval);
  723.             strcat(logstring, commastring);
  724.             strcat(logstring, "\nFree bytes:                              "); // these must be adjusted according to TRUNCATE
  725.             comma(size.freeval);
  726.             strcat(logstring, commastring);
  727.             strcat(logstring, "\n\n");
  728.             writeline();
  729.         }
  730.         GT_SetGadgetAttrs
  731.         (   LV81_Listview,
  732.             MainWindowPtr,
  733.             NULL,
  734.             GTLV_Labels, &SizeList,
  735.             TAG_DONE
  736.         );
  737.         showduplicates();
  738.     } else
  739.     {   GT_SetGadgetAttrs
  740.         (   TE81_Total,
  741.             MainWindowPtr, NULL,
  742.             GTTX_Text, "",
  743.             TAG_DONE
  744.         );
  745.         comma(size.freeval);
  746.         GT_SetGadgetAttrs
  747.         (   TE81_Free,
  748.             MainWindowPtr,
  749.             NULL,
  750.             GTTX_Text, "",
  751.             TAG_DONE
  752.         );
  753.         SetGadgetAttrs
  754.         (   gadgets[GID_8_LB1], MainWindowPtr, NULL,
  755.             LISTBROWSER_Labels, NULL,
  756.             TAG_END
  757.         );
  758.         if (DupNodes)
  759.         {   clearreactionlist(&DupList);
  760.             DupNodes = FALSE;
  761.         }
  762.         GT_SetGadgetAttrs
  763.         (   LV81_Listview,
  764.             MainWindowPtr,
  765.             NULL,
  766.             GTLV_Labels, &SizeList,
  767.             TAG_DONE
  768.         );
  769.     }
  770.  
  771.     GT_SetGadgetAttrs
  772.     (   BU99_Right,
  773.         MainWindowPtr, NULL,
  774.         GA_Disabled, FALSE,
  775.         TAG_DONE
  776.     );
  777.     GT_SetGadgetAttrs
  778.     (   BU99_Update,
  779.         MainWindowPtr, NULL,
  780.         GA_Disabled, FALSE,
  781.         TAG_DONE
  782.     );
  783.     GT_SetGadgetAttrs
  784.     (   BU99_Stop,
  785.         MainWindowPtr, NULL,
  786.         GA_Disabled, TRUE,
  787.         TAG_DONE
  788.     );
  789.     GT_SetGadgetAttrs
  790.     (   TE81_Status,
  791.         MainWindowPtr, NULL,
  792.         GTTX_Text, "Ready",
  793.         TAG_DONE
  794.     );
  795.  
  796.     if (LogFileHandle)
  797.     {   Close(LogFileHandle);
  798.         LogFileHandle = NULL;
  799.     }
  800.     while (FileNamesAllocated)
  801.     {   FreeMem(StackPtr[FileNamesAllocated], VLONGFIELD);
  802.         StackPtr[FileNamesAllocated--] = NULL;
  803.     }
  804.     FreeVec(StackPtr);
  805.     StackPtr = NULL;
  806.  
  807.     // We need the DirNamePtr[] array to remain valid, because
  808.     // the user can click on the listview gadget.
  809. }
  810.  
  811. MODULE void subdir(ULONG topdir)
  812. {   BOOL                 more;
  813.     TEXT                 tempstring[VLONGFIELD + 1];
  814.     struct ExAllControl* eac       = NULL;
  815.     struct ExAllData*    ead;
  816.  
  817.     /* Instead of passing a pointer to the path, we use a global string.
  818.     There are memory corruption problems if you pass pointers to variables
  819.     which are really local to other functions.
  820.  
  821.     This is dynamically allocated as it must be at least word-aligned;
  822.     also remember not to allocate large arrays on the stack. */
  823.  
  824.     if (!(DirHandle = (BPTR) Lock(globalname, ACCESS_READ)))
  825.     {   DisplayBeep(ScreenPtr);
  826.         return;
  827.     }
  828.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  829.     {   UnLock(DirHandle);
  830.         DirHandle = NULL;
  831.         rq("Can't allocate DOS object!");
  832.     }
  833.  
  834.     eac->eac_LastKey = 0;
  835.     do
  836.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 2048, ED_SIZE, eac);
  837.         if ((!more) && (IoErr() != ERROR_NO_MORE_ENTRIES))
  838.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  839.             eac = NULL;
  840.             UnLock(DirHandle);
  841.             DirHandle = NULL;
  842.             rq("Can't examine path!");
  843.         }
  844.         if (eac->eac_Entries == 0)
  845.         {   ; /* ExAll() failed normally with no entries */
  846.             continue; /* more is USUALLY zero */
  847.         }
  848.         ead = (struct ExAllData *) EADataPtr;
  849.  
  850.         do
  851.         {   /* use ead here */
  852.  
  853.             if (ead->ed_Type == 2) /* +2 is dir, +3 is softlink, -3 is file */
  854.             {   strcpy(tempstring, globalname);
  855.                 if (!AddPart(tempstring, ead->ed_Name, VLONGFIELD))
  856.                 {   FreeDosObject(DOS_EXALLCONTROL, eac);
  857.                     eac = NULL;
  858.                     UnLock(DirHandle);
  859.                     DirHandle = NULL;
  860.                     rq("Can't add filename to pathname!");
  861.                 }
  862.                 push(tempstring, topdir);
  863.             } elif (ead->ed_Type == -3) // if it's a file
  864.             {   addduplicate(&globalname[pathlength], ead->ed_Name);
  865.                 size.bytes[topdir] += ead->ed_Size;
  866.             }
  867.  
  868.             /* get next ead */
  869.             ead = ead->ed_Next;
  870.         } while(ead);
  871.     } while(more);
  872.  
  873.     FreeDosObject(DOS_EXALLCONTROL, eac);
  874.     eac = NULL;
  875.     UnLock(DirHandle);
  876.     DirHandle = NULL;
  877.     // don't call pop() yourself!
  878. }
  879.  
  880. MODULE void pop(void)
  881. {   ULONG breakval;
  882.  
  883.     pathlength = strlen(size.path);
  884.     while (size.stackentries && !stop)
  885.     {   size.stackentries--;
  886.         strcpy(globalname, StackPtr[size.stackentries + 1]);
  887.         subdir(size.topdir[size.stackentries + 1]);
  888.         breakval = checkbreak();
  889.         if (breakval == 2)
  890.             cleanexit(EXIT_SUCCESS);
  891.         elif (breakval == 1)
  892.             stop = TRUE;
  893. }   }
  894. MODULE void push(STRPTR name, ULONG theindex)
  895. {   size.stackentries++;
  896.     if (size.stackentries == LIMIT_DIRS)
  897.         rq("Overflow!");
  898.     if (size.stackentries > FileNamesAllocated)
  899.     {   if (!(StackPtr[FileNamesAllocated + 1] = AllocMem(VLONGFIELD, MEMF_PUBLIC)))
  900.             rq("Out of memory!");
  901.         FileNamesAllocated++;
  902.     }
  903.     strcpy(StackPtr[size.stackentries], name);
  904.     size.topdir[size.stackentries] = theindex;
  905. }
  906.  
  907. AGLOBAL void size_loop(ULONG class, struct Gadget* addr, UWORD code, UWORD qual)
  908. {   UWORD moveto;
  909.  
  910.     if (class == IDCMP_RAWKEY)
  911.     {   if (qual & IEQUALIFIER_CONTROL)
  912.         {   if (code == SCAN_UP)
  913.             {   GT_SetGadgetAttrs
  914.                 (   LV81_Listview,
  915.                     MainWindowPtr,
  916.                     NULL,
  917.                     GTLV_Top, 0,
  918.                     TAG_DONE
  919.                 );
  920.             } elif (code == SCAN_DOWN)
  921.             {   if (size.entries > 15)          // this number must change
  922.                 {   moveto = size.entries - 15; // if the height of the
  923.                 } else moveto = 0;              // listview changes
  924.                 GT_SetGadgetAttrs
  925.                 (   LV81_Listview,
  926.                     MainWindowPtr,
  927.                     NULL,
  928.                     GTLV_Top, moveto,
  929.                     TAG_DONE
  930.                 );
  931.     }   }   }
  932.     elif (class == IDCMP_VANILLAKEY)
  933.     {   code = toupper(code);
  934.         if (code == ESCAPE)
  935.         {   page = 0;
  936.         } elif (code == 'A')
  937.             parent();
  938.         elif (code == 'R')
  939.             root();
  940.         elif (code == '.')
  941.             pathasl();
  942.         elif (code == 'P')
  943.         {   ActivateGadget(ST81_Path, MainWindowPtr, NULL);
  944.         } elif (code == 'L')
  945.             fliplog(TRUE);
  946.         elif (code == 'O')
  947.         {   ActivateGadget(ST99_Output, MainWindowPtr, NULL);
  948.         } elif (code == 'U')
  949.             updatesize();
  950.         elif (code == 'D')
  951.         {   flipfind(TRUE);
  952.     }   }
  953.     elif (class == IDCMP_GADGETUP)
  954.     {   /* IDCMP_GADGETUP is sent by the string gadget
  955.         when the user presses RETURN, ENTER, Help, Tab
  956.         or Shift-Tab inside the string gadget. */
  957.  
  958.         if (addr == BU99_Right)
  959.         {   page = 0;
  960.         } elif (addr == BU99_Update)
  961.         {   updatesize();
  962.         } elif (addr == BU81_PathASL)
  963.         {   pathasl();
  964.         } elif (addr == ST81_Path)
  965.         {   pathstring();
  966.         } elif (addr == CB99_Log)
  967.         {   fliplog(FALSE);
  968.         } elif (addr == ST99_Output)
  969.         {   outputstring();
  970.         } elif (addr == BU99_OutputASL)
  971.         {   outputasl();
  972.         } elif (addr == BU81_Root)
  973.         {   root();
  974.         } elif (addr == BU81_Parent)
  975.         {   parent();
  976.         } elif (addr == CB81_Find)
  977.         {   flipfind(FALSE);
  978.         } elif (addr == LV81_Listview)
  979.         {   /* code is the position within the list, starting from 0. */
  980.  
  981.             if (code + 1 <= size.entries && size.type[code + 1] == 2)
  982.             {   if (!(AddPart(size.path, DirNamePtr[code + 1], VLONGFIELD + 1)))
  983.                     rq("Can't add filename to pathname!");
  984.                 else updatesize();
  985. }   }   }   }
  986.  
  987. AGLOBAL void size_exit(void)
  988. {   if (DirHandle)
  989.     {   UnLock(DirHandle);
  990.         DirHandle = NULL;
  991.     }
  992.     if (LogFileHandle)
  993.     {   Close(LogFileHandle);
  994.         LogFileHandle = NULL;
  995.     }
  996.  
  997.     // Only call this if the list gadget is detached or not present.
  998.     // (ie. after closewindow()).
  999.     if (SizeNodes)
  1000.     {   clearlist(&SizeList);
  1001.         SizeNodes = FALSE;
  1002.     }
  1003.     if (DupNodes)
  1004.     {   clearreactionlist(&DupList);
  1005.         DupNodes = FALSE;
  1006.     }
  1007.     while (FileNamesAllocated)
  1008.     {   FreeMem(StackPtr[FileNamesAllocated], VLONGFIELD);
  1009.         StackPtr[FileNamesAllocated--] = NULL;
  1010.     }
  1011.     if (StackPtr)
  1012.     {   FreeVec(StackPtr);
  1013.         StackPtr = NULL;
  1014.     }
  1015.     while ( DirNamesAllocated)
  1016.     {   FreeMem(DirNamePtr[DirNamesAllocated], VLONGFIELD);
  1017.         DirNamePtr[DirNamesAllocated--] = NULL;
  1018.     }
  1019.     if (DirNamePtr)
  1020.     {   FreeVec(DirNamePtr);
  1021.         DirNamePtr = NULL;
  1022. }   }
  1023.  
  1024. AGLOBAL void size_die(void)
  1025. {   if (EmptyColumnarNodes)
  1026.     {   clearreactionlist(&EmptyColumnarList);
  1027.         EmptyColumnarNodes = FALSE;
  1028.     }
  1029.     IOBuffer[6] = size.finddup;
  1030. }
  1031.  
  1032. AGLOBAL void size_config(void)
  1033. {   size.finddup = IOBuffer[6];
  1034. }
  1035.  
  1036. MODULE void parent(void)
  1037. {   BPTR DirHandle    = NULL,
  1038.          ParentHandle = NULL;
  1039.  
  1040.     if (!(DirHandle = (BPTR) Lock(size.path, ACCESS_READ)))
  1041.         rq("Can't lock directory!");
  1042.     if (!(ParentHandle = ParentDir(DirHandle)))
  1043.     {   /* It returned a NULL lock; ie. a lock on SYS:
  1044.         That is not what we want. */
  1045.         ParentHandle = DirHandle;
  1046.     }
  1047.     if (!NameFromLock(ParentHandle, size.path, VLONGFIELD))
  1048.         rq("Can't get name from lock!");
  1049.     UnLock(DirHandle);
  1050.     DirHandle = NULL;
  1051.  
  1052.     updatesize();
  1053. }
  1054.  
  1055. MODULE void root(void)
  1056. {   BPTR  DirHandle    = NULL,
  1057.           ParentHandle = NULL;
  1058.     ABOOL rootdone     = FALSE;
  1059.  
  1060.     if (!(DirHandle = (BPTR) Lock(size.path, ACCESS_READ)))
  1061.         rq("Can't lock directory!");
  1062.     do
  1063.     {   if (!(ParentHandle = ParentDir(DirHandle)))
  1064.         {   /* It returned a NULL lock; ie. a lock on SYS:
  1065.                That is not what we want. */
  1066.             ParentHandle = DirHandle;
  1067.             rootdone = TRUE;
  1068.         } else DirHandle = ParentHandle;
  1069.     } while (!rootdone);
  1070.     if (!NameFromLock(ParentHandle, size.path, VLONGFIELD))
  1071.         rq("Can't get name from lock!");
  1072.     UnLock(DirHandle);
  1073.     DirHandle = NULL;
  1074.  
  1075.     updatesize();
  1076. }
  1077.  
  1078. MODULE void pathasl(void)
  1079. {   strcpy(asldir, size.path);
  1080.     if (dirasl()) // path for ASL must be valid?
  1081.     {   strcpy(size.path, aslresult);
  1082.         GT_SetGadgetAttrs
  1083.         (   ST81_Path,
  1084.             MainWindowPtr, NULL,
  1085.             GTST_String, size.path,
  1086.             TAG_DONE
  1087.         );
  1088.         updatesize();
  1089. }   }
  1090.  
  1091. MODULE void pathstring(void)
  1092. {   strcpy
  1093.     (   size.path,
  1094.         ((struct StringInfo *) ST81_Path->SpecialInfo)->Buffer
  1095.     );
  1096.     updatesize();
  1097. }
  1098.  
  1099. MODULE void comma(ULONG value)
  1100. {   ABOOL yeah = FALSE;
  1101.  
  1102.     strcpy(commastring, " ,   ,   ,   ");
  1103.     //                    1   5   9
  1104.  
  1105.     valuestring[ 0] = '0' + (value / 1000000000);
  1106.     value %= 1000000000;
  1107.     if (valuestring[ 0] != '0')
  1108.     {   commastring[0] = valuestring[0];
  1109.         yeah = TRUE;
  1110.     } else
  1111.     {   commastring[ 0] = ' ';
  1112.         commastring[ 1] = ' ';
  1113.     }
  1114.  
  1115.     valuestring[ 1] = '0' + (value /  100000000);
  1116.     value %=  100000000;
  1117.     if (yeah || valuestring[1] != '0')
  1118.     {   commastring[2] = valuestring[1];
  1119.         yeah = TRUE;
  1120.     } else commastring[2] = ' ';
  1121.  
  1122.     valuestring[ 2] = '0' + (value /   10000000);
  1123.     value %=   10000000;
  1124.     if (yeah || valuestring[2] != '0')
  1125.     {   commastring[3] = valuestring[2];
  1126.         yeah = TRUE;
  1127.     } else commastring[3] = ' ';
  1128.  
  1129.     valuestring[ 3] = '0' + (value /    1000000);
  1130.     value %=    1000000;
  1131.     if (yeah || valuestring[3] != '0')
  1132.     {   commastring[4] = valuestring[3];
  1133.         yeah = TRUE;
  1134.     } else
  1135.     {   commastring[4] = ' ';
  1136.         commastring[5] = ' ';
  1137.     }
  1138.  
  1139.     valuestring[ 4] = '0' + (value /     100000);
  1140.     value %=     100000;
  1141.     if (yeah || valuestring[4] != '0')
  1142.     {   commastring[6] = valuestring[4];
  1143.         yeah = TRUE;
  1144.     } else commastring[6] = ' ';
  1145.  
  1146.     valuestring[ 5] = '0' + (value /      10000);
  1147.     value %=      10000;
  1148.     if (yeah || valuestring[5] != '0')
  1149.     {   commastring[7] = valuestring[5];
  1150.         yeah = TRUE;
  1151.     } else commastring[7] = ' ';
  1152.  
  1153.     valuestring[ 6] = '0' + (value /       1000);
  1154.     value %=       1000;
  1155.     if (yeah || valuestring[6] != '0')
  1156.     {   commastring[8] = valuestring[6];
  1157.         yeah = TRUE;
  1158.     } else
  1159.     {   commastring[8] = ' ';
  1160.         commastring[9] = ' ';
  1161.     }
  1162.  
  1163.     valuestring[ 7] = '0' + (value /        100);
  1164.     value %=        100;
  1165.     if (yeah || valuestring[7] != '0')
  1166.     {   commastring[10] = valuestring[7];
  1167.         yeah = TRUE;
  1168.     } else commastring[10] = ' ';
  1169.  
  1170.     valuestring[ 8] = '0' + (value /         10);
  1171.     value %=         10;
  1172.     if (yeah || valuestring[8] != '0')
  1173.     {   commastring[11] = valuestring[8];
  1174.         yeah = TRUE;
  1175.     } else commastring[11] = ' ';
  1176.  
  1177.     valuestring[ 9] = '0' +  value              ;
  1178.     commastring[12] = valuestring[9];
  1179. }
  1180.  
  1181. MODULE ABOOL dirasl(void)
  1182. {   struct FileRequester* ASLRqPtr;
  1183.     ABOOL                 success;
  1184.  
  1185.     if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, "~(#?.info)", ASL_Window, MainWindowPtr, ASL_ExtFlags1, FIL1F_NOFILES, TAG_DONE)))
  1186.     {   rq("Can't create ASL request!");
  1187.     }
  1188.     if (AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, "Report+ path selector", ASL_FuncFlags, FILF_PATGAD, TAG_DONE))
  1189.     {   strcpy(aslresult, ASLRqPtr->rf_Dir);
  1190.         success = TRUE;
  1191.     } else success = FALSE;
  1192.     FreeAslRequest(ASLRqPtr);
  1193.     return(success);
  1194. }
  1195.  
  1196. MODULE void showduplicates(void)
  1197. {   ULONG                 breakval, i, j, k, where;
  1198.     ABOOL                 found = FALSE,
  1199.                           started = FALSE,
  1200.                           success;
  1201.     struct DateTime       DateTime;
  1202.     LONG                  templength;
  1203.     struct FileInfoBlock* FIBPtr = NULL;
  1204.     TEXT                  pathnamestring[VLONGFIELD + 1],
  1205.                           commandstring[VLONGFIELD + 1],
  1206.                           lastfilename[VLONGFIELD + 1];
  1207.     struct Node*          ListBrowserNodePtr = NULL;
  1208.     STRPTR                tempPathnamePtr, tempFilenamePtr;
  1209.     ULONG                 firstpen, secondpen, currentpen, dups;
  1210.  
  1211.     DateTime.dat_Format  = FORMAT_DOS;
  1212.     DateTime.dat_Flags   = NULL;
  1213.     DateTime.dat_StrDay  = NULL;
  1214.     DateTime.dat_StrDate = datestring;
  1215.     DateTime.dat_StrTime = NULL;
  1216.  
  1217.     if (size.finddup)
  1218.     {   SetGadgetAttrs
  1219.         (   gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1220.             LISTBROWSER_Labels, NULL,
  1221.             TAG_END
  1222.         );
  1223.         if (DupNodes)
  1224.         {   clearreactionlist(&DupList);
  1225.             DupNodes = FALSE;
  1226.         }
  1227.         lockscreen();
  1228.         firstpen = FindColor
  1229.         (   ScreenPtr->ViewPort.ColorMap,
  1230.             0xDDDDDDDD,
  1231.             0xDDDDDDDD,
  1232.             0xDDDDDDDD,
  1233.             -1
  1234.         );
  1235.         secondpen = FindColor
  1236.         (   ScreenPtr->ViewPort.ColorMap,
  1237.             0xAAAAAAAA,
  1238.             0xAAAAAAAA,
  1239.             0xAAAAAAAA,
  1240.             -1
  1241.         );
  1242.         unlockscreen();
  1243.         currentpen = firstpen;
  1244.  
  1245.         if (shared.log)
  1246.         {   strcpy(logstring, "Duplicates found:\n");
  1247.             writeline();
  1248.         }
  1249.  
  1250.         /* Now we iterate through the complete file list (last entry index
  1251.         of files). For each file (i), we look at every other file (j). As
  1252.         soon as we find a matching file, we add the file (i) to the
  1253.         duplicate file list. */
  1254.  
  1255.         GT_SetGadgetAttrs
  1256.         (   TE81_Status,
  1257.             MainWindowPtr, NULL,
  1258.             GTTX_Text, "Matching",
  1259.             TAG_DONE
  1260.         );
  1261.         for (i = 1; i <= files; i++)
  1262.         {   breakval = checkbreak();
  1263.             if (breakval == 2)
  1264.             {   cleanexit(EXIT_SUCCESS);
  1265.             } elif (breakval == 1)
  1266.             {   stop = TRUE;
  1267.                 GT_SetGadgetAttrs
  1268.                 (   TE81_Status,
  1269.                     MainWindowPtr, NULL,
  1270.                     GTTX_Text, "Stopping",
  1271.                     TAG_DONE
  1272.                 );
  1273.                 break;
  1274.             }
  1275.             // if the user doesn't want us to stop...
  1276.             for (j = 1; j <= files; j++)
  1277.             {   if (i != j && !stricmp(FilenamePtr[i], FilenamePtr[j]))
  1278.                 {   found = TRUE; // we found (at least one) match
  1279.                     IsDup[i] = TRUE;
  1280.                     break;
  1281.         }   }   }
  1282.         if (!stop)
  1283.         {   GT_SetGadgetAttrs
  1284.             (   TE81_Status,
  1285.                 MainWindowPtr, NULL,
  1286.                 GTTX_Text, "Condense",
  1287.                 TAG_DONE
  1288.             );
  1289.  
  1290.             // condense list
  1291.             dups = 0;
  1292.             for (i = 1; i <= files; i++)
  1293.             {   if (IsDup[i])
  1294.                 {   dups++;
  1295.                     FilenamePtr[dups] = FilenamePtr[i];
  1296.                     PathnamePtr[dups] = PathnamePtr[i];
  1297.                     IsDup[dups]       = IsDup[i];
  1298.                 } else
  1299.                 {   FreeVec(PathnamePtr[i]);
  1300.                     FreeVec(FilenamePtr[i]);
  1301.             }   }
  1302.             GT_SetGadgetAttrs
  1303.             (   TE81_Status,
  1304.                 MainWindowPtr, NULL,
  1305.                 GTTX_Text, "Sorting",
  1306.                 TAG_DONE
  1307.             );
  1308.             // bubble sort routine
  1309.             for (i = dups; i >= 2; i--)
  1310.             {   for (j = 2; j <= i; j++) 
  1311.                 {   if (stricmp(FilenamePtr[j - 1], FilenamePtr[j]) > 0)
  1312.                     {   // swap them
  1313.                         tempPathnamePtr     = PathnamePtr[j - 1];
  1314.                         PathnamePtr[j - 1]  = PathnamePtr[j];
  1315.                         PathnamePtr[j]      = tempPathnamePtr;
  1316.                         tempFilenamePtr     = FilenamePtr[j - 1];
  1317.                         FilenamePtr[j - 1]  = FilenamePtr[j];
  1318.                         FilenamePtr[j]      = tempFilenamePtr;
  1319.             }   }   }
  1320.  
  1321.             GT_SetGadgetAttrs
  1322.             (   TE81_Status,
  1323.                 MainWindowPtr, NULL,
  1324.                 GTTX_Text, "Examine",
  1325.                 TAG_DONE
  1326.             );
  1327.             for (i = 1; i <= dups; i++)
  1328.             {   breakval = checkbreak();
  1329.                 if (breakval == 2)
  1330.                 {   cleanexit(EXIT_SUCCESS);
  1331.                 } elif (breakval == 1)
  1332.                 {   stop = TRUE;
  1333.                     GT_SetGadgetAttrs
  1334.                     (   TE81_Status,
  1335.                         MainWindowPtr, NULL,
  1336.                         GTTX_Text, "Stopping",
  1337.                         TAG_DONE
  1338.                     );
  1339.                     break;
  1340.                 }
  1341.  
  1342.                 // begin creating the line of text
  1343.                 if (PathnamePtr[i][0] == '/')
  1344.                 {   strcpy(liststring[0], &(PathnamePtr[i][1]));
  1345.                 } else
  1346.                 {   strcpy(liststring[0], PathnamePtr[i]);
  1347.                 }
  1348.                 strcpy(logstring, " ");
  1349.                 strcat(logstring, liststring[0]);
  1350.                 if (strlen(logstring) > TRUNCATE)
  1351.                 {   *(logstring + TRUNCATE) = 0; // truncate
  1352.                 }
  1353.                 templength = TRUNCATE + 1 - strlen(logstring);
  1354.                 if (templength >= 1)
  1355.                 {   for (k = 1; k <= templength; k++)
  1356.                     {   strcat(logstring, " ");
  1357.                 }   }
  1358.  
  1359.                 strcpy(pathnamestring, size.path);
  1360.                 if (PathnamePtr[i][0] != '/')
  1361.                 {   if (!AddPart(pathnamestring, PathnamePtr[i], 256))
  1362.                     {   rq("AddPart() failed!");
  1363.                 }   }
  1364.                 else
  1365.                 {   if (!AddPart(pathnamestring, &PathnamePtr[i][1], 256))
  1366.                     {   rq("AddPart() failed!");
  1367.                 }   }
  1368.                 success = FALSE;
  1369.  
  1370.                 // now get size and date of file
  1371.                 if (DirHandle  = (BPTR) Lock(pathnamestring, ACCESS_READ))
  1372.                 {   if (FIBPtr =        AllocDosObject(DOS_FIB, NULL))
  1373.                     {   success = TRUE;
  1374.  
  1375.                         if (Examine(DirHandle, FIBPtr))
  1376.                         {   comma(FIBPtr->fib_Size);
  1377.                             strcat(logstring, commastring);
  1378.                             for (j = 0; j <= 13; j++)
  1379.                             {   if (commastring[j] != ' ')
  1380.                                 {   where = j;
  1381.                                     break;
  1382.                             }   }
  1383.                             strcpy(liststring[1], &commastring[where]);
  1384.                         } else
  1385.                         {   strcpy(liststring[1], "?");
  1386.                             strcat(logstring, "            ?");
  1387.                         }
  1388.                         strcat(logstring, " ");
  1389.  
  1390.                         DateTime.dat_Stamp   = FIBPtr->fib_Date;
  1391.                         if (DateToStr(&DateTime))
  1392.                         {   strcpy(liststring[2], datestring);
  1393.                         } else
  1394.                         {   strcpy(liststring[2], "        ?");
  1395.                         }
  1396.                         strcat(logstring, liststring[2]);
  1397.                         strcat(logstring, " ");
  1398.  
  1399.                         FreeDosObject(DOS_FIB, FIBPtr);
  1400.                         FIBPtr = NULL;
  1401.                         UnLock(DirHandle);
  1402.                         DirHandle = NULL;
  1403.                 }   }
  1404.                 if (!success)
  1405.                 {   strcpy(liststring[1], "            ?");
  1406.                     strcpy(liststring[2], "        ?");
  1407.                     strcat(logstring, liststring[1]);
  1408.                     strcat(logstring, " ");
  1409.                     strcat(logstring, liststring[2]);
  1410.                     strcat(logstring, " ");
  1411.                 }
  1412.  
  1413.                 // now get the file version
  1414.                 strcpy(commandstring, "Version ");
  1415.                 strcat(commandstring, pathnamestring);
  1416.                 strcat(commandstring, " >T:ReportPlus.temp");
  1417.                 if (!SystemTags(commandstring, SYS_Output, Open("NIL:", MODE_NEWFILE), TAG_DONE))
  1418.                 {   readordie("T:ReportPlus.temp");
  1419.                     for (k = 0; k <= VLONGFIELD; k++)
  1420.                     {   if (IOBuffer[k] == LF)
  1421.                         {   IOBuffer[k] = 0;
  1422.                             break;
  1423.                     }   }
  1424.                     strcpy(liststring[3], IOBuffer);
  1425.                 } else
  1426.                 {   strcpy(liststring[3], "?");
  1427.                 }
  1428.                 strcat(logstring, liststring[3]);
  1429.  
  1430.                 if (started)
  1431.                 {   if (stricmp(FilenamePtr[i], lastfilename))
  1432.                     {   if (currentpen == firstpen)
  1433.                         {   currentpen = secondpen;
  1434.                         } else currentpen = firstpen;
  1435.                 }   }
  1436.                 else started = TRUE;
  1437.                 if (!(ListBrowserNodePtr = AllocListBrowserNode
  1438.                 (   4,                       // columns,
  1439.                     LBNA_Flags,              LBFLG_CUSTOMPENS,
  1440. /* LBNCA_ tags are those that apply to the specific column. */
  1441.                     LBNA_Column,             0,
  1442.                         LBNCA_CopyText,      TRUE,
  1443.                         LBNCA_Text,          liststring[0],
  1444.                         LBNCA_FGPen,         BLACK,
  1445.                         LBNCA_BGPen,         currentpen,
  1446.                     LBNA_Column,             1,
  1447.                         LBNCA_CopyText,      TRUE,
  1448.                         LBNCA_Text,          liststring[1],
  1449.                         LBNCA_Justification, LCJ_RIGHT,
  1450.                         LBNCA_FGPen,         BLACK,
  1451.                         LBNCA_BGPen,         currentpen,
  1452.                     LBNA_Column,             2,
  1453.                         LBNCA_CopyText,      TRUE,
  1454.                         LBNCA_Text,          liststring[2],
  1455.                         LBNCA_FGPen,         BLACK,
  1456.                         LBNCA_BGPen,         currentpen,
  1457.                     LBNA_Column,             3,
  1458.                         LBNCA_CopyText,      TRUE,
  1459.                         LBNCA_Text,          liststring[3], 
  1460.                         LBNCA_FGPen,         BLACK,
  1461.                         LBNCA_BGPen,         currentpen,
  1462.                     TAG_END
  1463.                 )))
  1464.                 {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  1465.                 }
  1466.                 AddTail(&DupList, ListBrowserNodePtr); // AddTail() has no return code
  1467.                 DupNodes = TRUE;
  1468.                 strcpy(lastfilename, FilenamePtr[i]);
  1469.                 
  1470.                 if (shared.log) // write to logfile
  1471.                 {   strcat(logstring, "\n");
  1472.                     writeline();
  1473.             }   }
  1474.             for (i = 1; i <= dups; i++)
  1475.             {   FreeVec(PathnamePtr[i]);
  1476.                 FreeVec(FilenamePtr[i]);
  1477.         }   }
  1478.         else
  1479.         {   for (i = 1; i <= files; i++)
  1480.             {   FreeVec(PathnamePtr[i]);
  1481.                 FreeVec(FilenamePtr[i]);
  1482.         }   }
  1483.         files = 0;
  1484.         FreeVec(IsDup);
  1485.         IsDup = NULL;
  1486.         FreeVec(PathnamePtr);
  1487.         PathnamePtr = NULL;
  1488.         FreeVec(FilenamePtr);
  1489.         FilenamePtr = NULL;
  1490.         DeleteFile("T:ReportPlus.temp"); /* returns FALSE for failure */
  1491.  
  1492.         if (shared.log)
  1493.         {   if (!found)
  1494.             {   strcpy(logstring, " None\n");
  1495.             }
  1496.             strcat(logstring, "\n");
  1497.             writeline();
  1498.         }
  1499.  
  1500.         SetGadgetAttrs
  1501.         (   gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1502.             LISTBROWSER_Labels, &DupList,
  1503.             TAG_END
  1504.         );
  1505. }   }
  1506.  
  1507. MODULE void addduplicate(STRPTR path, STRPTR filename)
  1508. {   TEXT tablestring[257];
  1509.  
  1510.     if (size.finddup)
  1511.     {   files++;
  1512.         if (files >= MAX_FILES)
  1513.         {   rq("Too many files!");
  1514.         }
  1515.         IsDup[files] = FALSE;
  1516.  
  1517.         if (!(FilenamePtr[files] = AllocVec(strlen(filename) + 1, NULL)))
  1518.         {   rq("Out of memory!");
  1519.         }
  1520.         strcpy(FilenamePtr[files], filename);
  1521.  
  1522.         strcpy(tablestring, path);
  1523.         if (!AddPart(tablestring, filename, 256))
  1524.         {   rq("AddPart() failed!");
  1525.         }
  1526.         if (!(PathnamePtr[files] = AllocVec(strlen(tablestring) + 1, NULL)))
  1527.         {   rq("Out of memory!");
  1528.         }
  1529.         strcpy(PathnamePtr[files], tablestring);
  1530.  
  1531.     /* size.path   path           filename    PathnamePtr[]           FilenamePtr[]
  1532.        "SYS:Tools" "Commodities/" "AutoPoint" "Commodities/AutoPoint" "AutoPoint" */
  1533. }   }
  1534.  
  1535. MODULE void flipfind(ABOOL keyboard)
  1536. {   if (keyboard)
  1537.     {   if (CB81_Find->Flags & GFLG_SELECTED)
  1538.         {   size.finddup = FALSE;
  1539.         } else
  1540.         {   size.finddup = TRUE;
  1541.     }   }
  1542.     else
  1543.     {   if (CB81_Find->Flags & GFLG_SELECTED)
  1544.         {   size.finddup = TRUE;
  1545.         } else
  1546.         {   size.finddup = FALSE;
  1547.     }   }
  1548.  
  1549.     GT_SetGadgetAttrs
  1550.     (   CB81_Find,
  1551.         MainWindowPtr, NULL,
  1552.         GTCB_Checked, size.finddup,
  1553.         TAG_DONE
  1554.     );
  1555.     SetGadgetAttrs
  1556.     (   gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1557.         GA_Disabled, !size.finddup,
  1558.         TAG_END
  1559.     );
  1560. }
  1561.  
  1562. MODULE void writeline(void)
  1563. {   /* The file is opened just before the first call to writeline()
  1564.     (when the date, time, etc. is written). Then we keep the file open
  1565.     and do our scan. Then we write out the results a line at a time,
  1566.     then the free and total bytes.
  1567.       If we are also doing duplicates, we now do our thinking,
  1568.     write the results a line at a time, then close the file. */
  1569.  
  1570.     if (FPuts(LogFileHandle, logstring))
  1571.     {   Close(LogFileHandle);
  1572.         LogFileHandle = NULL;
  1573.         rq("Can't append to file!");
  1574. }   }
  1575.  
  1576.